/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.tom.social.common.jade;

import jade.core.AID;
import jade.core.Agent;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.SearchConstraints;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;
import jade.util.leap.Iterator;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.wrapper.ControllerException;
import jade.wrapper.StaleProxyException;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import pl.tom.social.common.types.ConversationIDType;

/**
 *
 * @author Tom
 */
public abstract class JadeHandler {

	private static final Logger logger = Logger.getLogger(JadeHandler.class);
	protected AgentContainer container = null;
	protected Agent admin;

	public AgentContainer getContainer() {
		if(container == null) {
			connectToMainContainer();
		}
		return container;
	}

	public abstract void connectToMainContainer();

	public synchronized void stopJade() {
		if(container != null) {
			logger.log(Level.DEBUG, "Terminating JADE");
			try {
				container.kill();
			} catch(StaleProxyException ex) {
				logger.log(Level.ERROR, null, ex);
			}
		}
	}

	public synchronized AID getTaskBarAgent(Agent agent) {
		try {
			//TODO creale enum with agent names
			String serviceType = "global";
			DFAgentDescription[] results = getServices(agent, serviceType);
			logger.log(Level.DEBUG, results.length + " services found.");
			for(int i = 0; i < results.length; ++i) {
				DFAgentDescription dfd = results[i];
				AID provider = dfd.getName();
				Iterator it = dfd.getAllServices();
				while(it.hasNext()) {
					ServiceDescription sd = (ServiceDescription) it.next();
					if(sd.getType().equals(serviceType)) {
						ACLMessage msg = new ACLMessage(ACLMessage.REQUEST);
						msg.addReceiver(provider);
						msg.setConversationId(ConversationIDType.GetTaskBar.name());
						msg.setContent(agent.getLocalName());
						agent.send(msg);

						msg = agent.blockingReceive(10000);
						if(msg != null && msg.getPerformative() == ACLMessage.SUBSCRIBE) {
							return msg.getSender();
						}
					}
				}
			}
		} catch(FIPAException ex) {
			logger.log(Level.ERROR, ex);
		}
		return null;
	}

	protected void addAgent(Agent agent, String agentName) {
		try {
			AgentController ac = getContainer().acceptNewAgent(agentName, agent);
			ac.start();
			logger.log(Level.DEBUG, agentName + " started");
		} catch(StaleProxyException ex) {
			logger.log(Level.ERROR, null, ex);
		}
	}

	protected void deleteAgent(String agentName) {
		try {
			AgentController ac = getContainer().getAgent(agentName);
			//TODO does not seem to stop the agent
			ac.kill();
			logger.log(Level.DEBUG, agentName + " killed");
		} catch(ControllerException ex) {
			logger.log(Level.ERROR, null, ex);
		}
	}

	protected void notifyGlobal(int performative) {
		String serviceType = "global";
		DFAgentDescription[] results = null;
		try {
			results = getServices(admin, serviceType);
		} catch (FIPAException ex) {
			logger.log(Level.ERROR, null, ex);
		}
		logger.log(Level.DEBUG, results != null ? results.length : 0 + " " + serviceType + " services found.");
		sendMessage(results, null, serviceType, ConversationIDType.Notify, performative);
	}

	protected void sendMessage(DFAgentDescription[] results, String content, String serviceType,
			ConversationIDType conversationType, int performative) {
		for(int i = 0; i < results.length; ++i) {
			DFAgentDescription dfd = results[i];
			AID provider = dfd.getName();
			Iterator it = dfd.getAllServices();
			while(it.hasNext()) {
				ServiceDescription sd = (ServiceDescription) it.next();
				if(sd.getType().equals(serviceType)) {
					ACLMessage msg = new ACLMessage(performative);
					msg.setContent(content);
					msg.addReceiver(provider);
					msg.setConversationId(conversationType.name());
					admin.send(msg);

					logger.log(Level.DEBUG,
							"Message send to " + provider.getName() + ", content:" + msg.getContent());

					break;
				}
			}
		}
	}

	public static DFAgentDescription[] getServices(Agent agent, String serviceType) throws FIPAException {
		DFAgentDescription template = new DFAgentDescription();
		ServiceDescription templateSd = new ServiceDescription();
		templateSd.setType(serviceType);
		template.addServices(templateSd);
		SearchConstraints sc = new SearchConstraints();
		DFAgentDescription[] results = DFService.search(agent, template, sc);
		return results;
	}

	public static void registerAgent(Agent agent, AID aid, String name) throws FIPAException {
		DFAgentDescription dfd = new DFAgentDescription();
		dfd.setName(aid);
		ServiceDescription sd = new ServiceDescription();
		sd.setType(name);
		sd.setName(name);
		dfd.addServices(sd);
		DFService.register(agent, dfd);
	}
}
